/*
 *  $Id: Button.cs 715 2009-07-18 15:26:07Z thenn.erannor $
 *	This file is a part of Ragima CCG.
 *	(C) 2008 Ragima development group.
 *
 *	Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System;
using System.Collections.Generic;

using AgateLib.DisplayLib;
using AgateLib.Geometry;

namespace Ragima.Menu {
    public class Button: Region {
        private Surface _button;
        private SimpleEvent _action;
        private List<ButtonInstance> _instances, _instancesAdd;
        private ButtonInstance _main;

        public Button(Surface button, SimpleEvent action): base(Rectangle.Empty) {
            _button = button;
            _action = action;
            _instances = new List<ButtonInstance>();
            _instancesAdd = new List<ButtonInstance>();
            _main = new ButtonMainInstance();
            _instances.Add(_main);
        }

        public int InstanceCount { get { return _instances.Count; } }

        private void AddInstance(ButtonInstance instance) {
            _instancesAdd.Add(instance);
        }

        public override void Draw() {
            Point pos = Rect.Location;
            for (int i = _instances.Count-1; i >= 0; i--) {
                ButtonInstance instance = _instances[i];
                _button.RotationAngleDegrees = instance.Angle;
                _button.Color = Color.FromArgb(instance.Alpha, Color.White);
                _button.Draw(pos.X + instance.Offset.X, pos.Y + instance.Offset.Y);
            }
        }

        public override void OnProcess() {
            _instances.RemoveAll(delegate(ButtonInstance instance) { return instance.NeedDelete(); });
            foreach (ButtonInstance instance in _instances) instance.Process(this);
            if (_instancesAdd.Count > 0) {
                _instances.AddRange(_instancesAdd);
                _instancesAdd.Clear();
            }
        }

        private const int MaxFocusInstances = 20;

        public override void OnMouseEnter() {
            base.OnMouseEnter();
            int count = 0;
            foreach (ButtonInstance instance in _instances)
                if (instance is ButtonFocusInstance) count++;
            int max = Math.Min(MaxFocusInstances - count, 4);
            for (int i = 0; i < max; i++)
                AddInstance(new ButtonFocusInstance(_main.Angle));
        }

        public override void OnClickUp() {
            if (_action != null) _action();
        }

        private abstract class ButtonInstance {
            public double Angle;
            public int Alpha;
            public PointF Offset;

            public ButtonInstance() {
                Angle = 0;
                Alpha = 255;
                Offset = PointF.Empty;
            }

            public virtual bool NeedDelete() {
                return false;
            }

            public virtual void Process(Button button) {}
        }

        private class ButtonMainInstance: ButtonInstance {
            private double _angleTarget;
            private bool _angleDir;

            public ButtonMainInstance(): base() {
                _angleDir = Randomizer.Global.Next(2) == 0;
                NewAngle();
            }

            private const double AngleStep = 0.02;

            public override void Process(Button button) {
                if (button.Focus && Math.Abs(Angle) < AngleStep) {
                    Angle = 0;
                    return;
                }
                bool change;
                if (_angleDir) {
                    Angle += AngleStep;
                    change = (Angle >= _angleTarget);
                } else {
                    Angle -= AngleStep;
                    change = (Angle <= _angleTarget);
                }
                if (change) {
                    _angleDir = !_angleDir;
                    NewAngle();
                    button.AddInstance(new ButtonShadowInstance(Angle));
                }
            }

            public void NewAngle() {
                _angleTarget = Randomizer.Global.Next(30, 60) / 10.0 * (_angleDir ? 1 : -1);
            }
        }

        private class ButtonShadowInstance: ButtonInstance {
            public ButtonShadowInstance(double angle): base() {
                Angle = angle;
                Alpha = 100;
            }

            public override bool NeedDelete() {
                return Alpha == 0;
            }

            private const int AlphaStep = 1;

            public override void Process(Button button) {
                Alpha = Math.Max(Alpha - AlphaStep, 0);
            }
        }

        private class ButtonFocusInstance: ButtonInstance {
            private double _direction;
            private int _time, _startTime;
            private bool _del;

            public ButtonFocusInstance(double angle): base() {
                Angle = angle;
                _del = false;
                NewDirection();
            }

            public override bool NeedDelete() {
                return _time == 0 && _del;
            }

            private const int StartAlpha = 120;
            private const int MinTime = 50;
            private const int MaxTime = 200;
            private const double MoveStep = 0.1;

            public override void Process(Button button) {
                if (_time > 0)
                    _time--;
                else
                    NewDirection();
                Alpha = StartAlpha*_time/_startTime;
                double r = MoveStep*(_startTime-_time);
                Offset.X = (float) (Math.Sin(_direction)*r);
                Offset.Y = (float) (Math.Cos(_direction)*r);
                _del = !button.Focus;
            }

            private void NewDirection() {
                Alpha = StartAlpha;
                Offset = PointF.Empty;
                _direction = Randomizer.Global.Next(360)/180.0*Math.PI;
                _startTime = Randomizer.Global.Next(MinTime, MaxTime);
                _time = _startTime;
            }
        }
    }
}